/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.uml2.uml.NamedElement;

import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.MoveAnchorCommand;
import com.cea.papyrus.diagram.sequence.sedi.figures.AnchoringFigure;
import com.cea.papyrus.diagram.sequence.sedi.figures.MessageAccess;
import com.cea.papyrus.diagram.sequence.sedi.figures.MessageProxy;
import com.cea.papyrus.diagram.sequence.sedi.figures.SeDiAnchor;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;

/**
 * This class implements the EditPart-side support for anchoring objects. Although we
 * consider anchoring a purely graphical/editor-related subject, it needs some association
 * with the model now and then. For example, when an EO is put on a lifeline, some of the
 * messages there might glue to the left side of the EO whereas others prefer the right
 * side. This preference must be propagated to the model somehow. However, the figure
 * itself has no knowledge of the model. So this is where the EditPart comes in, as the
 * controller that ties the model and the figure together.
 * 
 * @see MessageAccess
 * @see MessageProxy
 * @see AnchoringFigure
 * @author frankd@ifi.uio.no
 */
public abstract class AnchoringEditPart<T extends NamedElement> extends SeDiSubpartEditPart<T>
        implements MessageAccess {

    public AnchoringEditPart(GraphElement model, ModelManager modelManager) {
        super(model, modelManager);
    }

    public MessageProxy[] getMessages(String ref) {
        final List<MessageProxy> proxies = new LinkedList<MessageProxy>();

        List<?> candidateList = getSourceConnections();
        Iterator<?> i = candidateList.iterator();
        while (i.hasNext()) {
            ConnectionEditPart candidate = (ConnectionEditPart) i.next();
            GraphEdge message = (GraphEdge) candidate.getModel();
            if (ModelUtil.getSourceRef(message).equals(ref)) {
                proxies.add(new MessageProxyImpl(candidate, true));
            }
        }

        candidateList = getTargetConnections();
        i = candidateList.iterator();
        while (i.hasNext()) {
            ConnectionEditPart candidate = (ConnectionEditPart) i.next();
            GraphEdge message = (GraphEdge) candidate.getModel();
            if (ModelUtil.getTargetRef(message).equals(ref)) {
                proxies.add(new MessageProxyImpl(candidate, false));
            }
        }

        return (MessageProxy[]) proxies.toArray(new MessageProxy[proxies.size()]);
    }

    private class MessageProxyImpl implements MessageProxy {
        private final ConnectionEditPart link;
        private final boolean sourceAnchor;

        public MessageProxyImpl(final ConnectionEditPart connection, final boolean sourceAnchor) {
            this.link = connection;
            this.sourceAnchor = sourceAnchor;
        }

        public ConnectionAnchor getOtherAnchor() {
            if (sourceAnchor) {
                NodeEditPart targetEP = (NodeEditPart) link.getTarget();
                return targetEP.getTargetConnectionAnchor(link);
            } else {
                NodeEditPart sourceEP = (NodeEditPart) link.getSource();
                return sourceEP.getSourceConnectionAnchor(link);
            }
        }

        public void updateMyAnchor(final String tag) {
            // These updates should occur inside the same command that
            // causes the update in the first place
            final GraphEdge model = (GraphEdge) link.getModel();
            AnchoringFigure figure = (AnchoringFigure) getFigure();
            ConnectionAnchor anchor = figure.getAnchor(tag);
            Point p = anchor.getLocation(anchor.getReferencePoint()).getCopy();
            figure.translateToAbsolute(p);
            SeDiAnchor seDiAnchor = null;
            if (anchor instanceof SeDiAnchor) {
                seDiAnchor = (SeDiAnchor) anchor;
            }
            if (sourceAnchor) {
                if (seDiAnchor != null)
                    model.getAnchor().get(0).setPosition(
                            new Point(seDiAnchor.getOffsetX(), seDiAnchor.getOffsetY()));
            } else {
                if (seDiAnchor != null)
                    model.getAnchor().get(1).setPosition(
                            new Point(seDiAnchor.getOffsetX(), seDiAnchor.getOffsetY()));
            }
            // Dont use command stack.
            // getViewer().getEditDomain().getCommandStack().execute(
            // new MoveAnchorCommand(model, tag, sourceAnchor));
            new MoveAnchorCommand(model, tag, sourceAnchor).execute();
            refresh();
        }
    }

//    /**
//     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#refresh()
//     */
//    @Override
//    public void refresh() {
//        super.refresh();
//        //
//        // refresh message
//        GraphElement graphElement = LookForElement.getDiagram((GraphElement) this.getModel());
//        Iterator<EObject> iterElements = graphElement.eAllContents();
//        EditPart editPart = getRoot();
//        while (iterElements.hasNext()) {
//            Object object = iterElements.next();
//            if (object instanceof GraphEdge) {
//                EditPart editPart2 =
//                        (EditPart) editPart.getViewer().getEditPartRegistry().get(object);
//                if (editPart2 instanceof MessageEditPart) {
//                    editPart2.refresh();
//                }
//            }
//        }
//    }
}
